package cn.nn200433.controller;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import cn.hutool.system.SystemUtil;
import cn.nn200433.common.BaiDuFy;
import cn.nn200433.db.DbToWord;
import cn.nn200433.db.entity.DbParam;
import cn.nn200433.swagger.SwaggerToWord;
import cn.nn200433.swagger.entity.SwaggerParam;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * 主控制器
 *
 * @author song_jx
 * @date 2022-03-24 06:56:14
 */
@Controller
public class IndexController {

    private static final Log log = LogFactory.get();

    private static final String SWAGGER_TPL = "swagger/tpl_swagger.docx";
    private static final String DB_TPL = "db/tpl_db.docx";
    private static final String SWAGGER_DIR = SystemUtil.get(SystemUtil.TMPDIR) + File.separator + "swagger" + File.separator;
    private static final String DB_DIR = SystemUtil.get(SystemUtil.TMPDIR) + File.separator + "db" + File.separator;

    @GetMapping("index")
    public String edit(Model model, HttpServletRequest request) {
        //加入公用参数的
        String contextPath = request.getServletContext().getContextPath();
        String serverPath = request.getScheme() + "://" + request.getLocalAddr() + ":" + request.getLocalPort();
        String ctx = StrUtil.isBlank(contextPath) ? serverPath : serverPath + "/" + contextPath;
        model.addAttribute("ctx", ctx);
        return "index.html";
    }

    @ResponseBody
    @PostMapping("swagger/toWord")
    public JSONObject swagger2word(@Validated @RequestBody SwaggerParam param) {
        long current = DateUtil.current();
        JSONObject result = new JSONObject(2);
        try {
            String swaggerUrl = param.getSwaggerUrl();
            String documentName = param.getDocumentName();
            log.info("======> 【Swagger】 开始导出文档 {}", swaggerUrl);
            List<Map<String, String>> groupList = Collections.emptyList();
            try {
                groupList = getSwaggerGroupList(swaggerUrl + "/swagger-resources");
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }

            String exportFileDir = SWAGGER_DIR + current + File.separator;
            String exportZipFile = SWAGGER_DIR + current + ".zip";
            FileUtil.mkdir(exportFileDir);

            SwaggerToWord swaggerToWord = new SwaggerToWord();
            for (Map<String, String> group : groupList) {
                InputStream tplStream = ResourceUtil.getStream(SWAGGER_TPL);
                // region 处理url中的中文字符串
                String name = group.get("name");
                log.info("======> 【Swagger】 准备处理分组 {} ...", name);
                String encode = URLEncoder.encode(name, CharsetUtil.UTF_8);
                String url = swaggerUrl + group.get("url");
                // endregion

                String exportFile = exportFileDir + name + ".docx";
                if (param.getAutoTranslate()) {
                    swaggerToWord.transform(url.replace(name, encode), documentName, tplStream, exportFile, new BaiDuFy(param.getBaiduAppId(), param.getBaiduAppKey()));
                } else {
                    swaggerToWord.transform(url.replace(name, encode), documentName, tplStream, exportFile, null);
                }
                IoUtil.close(tplStream);
            }

            // 打包
            log.info("======> 【Swagger】 开始打包文档...");
            File zipFile = ZipUtil.zip(exportFileDir, exportZipFile, CharsetUtil.CHARSET_UTF_8, Boolean.FALSE);
            log.info("======> 【Swagger】 打包完成，路径 = {}", zipFile.getAbsolutePath());
            result.put("code", "1");
            result.put("path", zipFile.getName());
        } catch (Exception e) {
            result.put("code", "0");
            result.put("error", "错误原因：" + e.getMessage());
            log.error(e);
        }
        return result;
    }

    @GetMapping("swagger/download/{downloadFile}")
    public void swaggerDownload(@PathVariable(value = "downloadFile") String downloadFile,
                                @RequestParam(value = "fileName", required = false) String fileName,
                                HttpServletResponse response) throws Exception {
        File zipFile = new File(SWAGGER_DIR + downloadFile);
        // 设置编码格式
        fileName = StrUtil.blankToDefault(fileName, zipFile.getName());
        if (!StrUtil.contains(fileName, ".zip")) {
            fileName += ".zip";
        }

        downloadFile(zipFile, fileName, response);

        // 删除文件 及 文件夹
        String zipSourceDir = FileUtil.mainName(zipFile);
        FileUtil.del(zipSourceDir);
        FileUtil.del(zipFile);
    }

    @ResponseBody
    @PostMapping("db/toWord")
    public JSONObject db2word(@Validated @RequestBody DbParam dbParam) {
        JSONObject result = new JSONObject(2);
        try {
            log.info("======> 【数据库】 开始导出文档 {}", dbParam.getJdbcUrl());
            FileUtil.mkdir(DB_DIR);
            String fileName = dbParam.getDbDocumentName() + StrUtil.UNDERLINE + DateUtil.current() + ".docx";
            String exportFile = DB_DIR + fileName;
            InputStream tplStream = ResourceUtil.getStream(DB_TPL);
            new DbToWord().transform(dbParam, tplStream, exportFile);
            IoUtil.close(tplStream);

            log.info("======> 【数据库】 导出完成，路径 = {}", exportFile);
            result.put("code", "1");
            result.put("path", fileName);
        } catch (Exception e) {
            result.put("code", "0");
            result.put("error", "错误原因：" + e.getMessage());
            log.error(e);
        }
        return result;
    }

    @GetMapping("db/download/{downloadFile}")
    public void dbDownload(@PathVariable(value = "downloadFile") String downloadFile,
                           @RequestParam(value = "fileName", required = false) String fileName,
                           HttpServletResponse response) throws Exception {
        File dbFile = new File(DB_DIR + downloadFile);
        // 设置编码格式
        fileName = StrUtil.blankToDefault(fileName, dbFile.getName());
        if (!StrUtil.contains(fileName, ".docx")) {
            fileName += ".docx";
        }

        downloadFile(dbFile, fileName, response);

        // 删除文件
        FileUtil.del(dbFile);
    }

    /**
     * 下载文件
     *
     * @param downloadFile 待下载的文件
     * @param fileName     文件名称
     * @param response     响应
     * @throws IOException ioexception
     * @author song_jx
     */
    private void downloadFile(File downloadFile, String fileName, HttpServletResponse response) throws IOException {
        // 重置response
        response.reset();
        // 设置response的Header
        response.setCharacterEncoding("UTF-8");
        // ContentType，即告诉客户端所发送的数据属于什么类型
        response.setContentType("application/octet-stream;charset=UTF-8");
        // 获得文件的长度
        response.addHeader("Content-Length", Convert.toStr(downloadFile.length()));
        // 设置编码格式
        response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileName, "UTF-8"));
        // 发送给客户端的数据
        ServletOutputStream out = response.getOutputStream();
        out.write(FileUtil.readBytes(downloadFile));
        out.flush();
        out.close();
    }

    /**
     * 获取swagger分组列表
     *
     * @param swaggerGroupUrl swagger组url
     * @return {@link List }<{@link Map }<{@link String }, {@link String }>>
     * @throws Exception 异常
     * @author song_jx
     */
    private List<Map<String, String>> getSwaggerGroupList(String swaggerGroupUrl) throws Exception {
        return JSON.parseObject(HttpUtil.get(swaggerGroupUrl), new TypeReference<List<Map<String, String>>>() {
        });
    }

}